package com.iotmonitor.iot.service.impl;

import com.google.common.collect.Lists;
import com.iotmonitor.common.core.constant.SystemDefinition;
import com.iotmonitor.common.core.utils.StringUtils;
import com.iotmonitor.common.redis.service.RedisService;
import com.iotmonitor.iot.es.ESRepository;
import com.iotmonitor.iot.service.ITbQuotaService;
import com.iotmonitor.iot.service.TbDeviceService;
import com.iotmonitor.iot.domain.dto.DeviceDTO;
import com.iotmonitor.iot.domain.dto.QuotaInfo;
import com.iotmonitor.iot.domain.vo.DeviceQuotaVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.rest.RestStatus;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class TbDeviceServiceImpl implements TbDeviceService {


    @Autowired
    private ESRepository esRepository;

    @Autowired
    private ITbQuotaService quotaService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisService redisService;


    @Override
    public boolean setStatus(String deviceId, Boolean status) {
        DeviceDTO deviceDTO = findDevice(deviceId);
        if (deviceDTO == null) {
            return false;
        }
        boolean b = esRepository.updateStatus(deviceId, status);
        deviceDTO.setStatus(status);
        refreshDevice(deviceDTO);
        return b;
    }

    @Override
    public boolean updateTags(String deviceId, String tags) {
        DeviceDTO deviceDTO = findDevice(deviceId);
        if (deviceDTO == null) {
            return false;
        }
        return esRepository.updateDeviceTag(deviceId, tags);
    }

    @Override
    public List<DeviceDTO> queryPage(Integer page, Integer pageSize, String deviceId, String tags, Integer state) {
        return esRepository.searchDevice(page, pageSize, deviceId, tags, state);
    }

    @Override
    public boolean saveDeviceInfo(DeviceDTO deviceDTO) {
        // 查询设备 ，判断开关状态 ，如果是关闭则不处理
        DeviceDTO device = findDevice(deviceDTO.getDeviceId());
        if (device != null && !device.getStatus()) {
            return false;
        }
        // 如果当前设备查不到，新增
        if (device == null) {
            esRepository.addDevices(deviceDTO);
        } else {
            // 如果可以查询到，更新告警信息
            try {
                esRepository.updateDevicesAlarm(deviceDTO);
            }catch (ElasticsearchStatusException e){
                if (e.status() == RestStatus.NOT_FOUND){
                    // 如果es中没有信息可以更新，则添加该数据
                    log.error("es未找到可更新记录，正在插入本记录...");
                    esRepository.addDevices(deviceDTO);
                }
            }
        }
        refreshDevice(deviceDTO);
        return true;
    }

    @Override
    public void updateOnLine(String deviceId, Boolean online) {
        // 以webclient开头的client为系统前端,monitor开头的是亿可控服务端
        if (deviceId.startsWith("webclient") || deviceId.startsWith("monitor")) {
            return;
        }
        // 更新数据到es
        DeviceDTO deviceDTO = findDevice(deviceId);
        if (deviceDTO == null) {
            return;
        }
        esRepository.updateOnline(deviceId, online);
        deviceDTO.setOnline(online);
        refreshDevice(deviceDTO);

    }


    @Override
    public List<DeviceQuotaVO> queryDeviceQuota(Integer page, Integer pageSize, String deviceId, String tag, Integer state) {

        // 1.查询设备列表
        List<DeviceDTO> pager = esRepository.searchDevice(page, pageSize, deviceId, tag, state);
        // 2.查询指标列表
        List<DeviceQuotaVO> deviceQuotaVOList = Lists.newArrayList();
        pager.forEach(deviceDTO -> {
            DeviceQuotaVO deviceQuotaVO = new DeviceQuotaVO();
            BeanUtils.copyProperties(deviceDTO, deviceQuotaVO);
            // 查询指标
            List<QuotaInfo> quotaList = quotaService.getLastQuotaList(deviceDTO.getDeviceId());
            deviceQuotaVO.setQuotaList(quotaList);
            deviceQuotaVOList.add(deviceQuotaVO);
        });

        return deviceQuotaVOList;
    }


    /**
     * 根据设备id查询设备
     *
     * @param deviceId
     * @return
     */
    @Override
    public DeviceDTO findDevice(String deviceId) {
        DeviceDTO deviceDTO = (DeviceDTO) redisTemplate.boundHashOps(SystemDefinition.DEVICE_KEY).get(deviceId);
        if (deviceDTO == null) {
            deviceDTO = esRepository.searchDeviceById(deviceId);
            refreshDevice(deviceDTO);
        }
        return deviceDTO;
    }


    @Override
    public boolean addTag(String deviceId, String tag) {
        DeviceDTO device = esRepository.searchDeviceById(deviceId);
        if(device == null){
            return false;
        }
        String tags = device.getTag();
        if (StringUtils.isNotEmpty(tags) && tags.contains(tag)){
            return false;
        }else if (StringUtils.isNotEmpty(tags)){
            tags = Stream.concat(Arrays.stream(tags.split(",")), Stream.of(tag)).collect(Collectors.joining(","));
        }else {
            tags = tag;
        }
        return updateTags(deviceId, tags);
    }

    @Override
    public boolean deleteTag(String deviceId, String tag) {
        DeviceDTO device = esRepository.searchDeviceById(deviceId);
        if(device == null){
            return false;
        }
        String tags = device.getTag();
        if (StringUtils.isEmpty(tags) || !tags.contains(tag)){
            return false;
        }else {
            tags = Arrays.stream(tags.split(",")).filter(e -> !tag.equals(e)).collect(Collectors.joining(","));
        }
        return updateTags(deviceId, tags);
    }

    /**
     * 刷新缓存
     *
     * @param deviceDTO
     */
    private void refreshDevice(DeviceDTO deviceDTO) {
        if (deviceDTO == null) {
            return;
        }
        redisTemplate.boundHashOps(SystemDefinition.DEVICE_KEY).put(deviceDTO.getDeviceId(), deviceDTO);
    }


}
